package net.mohas.docsearch.controller;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.Writer;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Iterator;
import java.util.List;

import org.apache.lucene.analysis.Analyzer;

import cern.colt.matrix.DoubleMatrix2D;

/**
 *
 * @author Muhammad
 */
public class Indexing {

    private String namaberkas;
    private String lokasiberkas;
    private DatabaseOperation odb;
    private TextOperation ot;
    private MatrixOperation om;


    public Indexing(TextOperation ot) {
        this.ot = ot;
        System.out.println("Kelas Pengindeksan(" + ot.getClass().getSimpleName() + ") terdefinisi.");
    }

    public String getLokasiberkas() {
        return lokasiberkas;
    }

    public void setLokasiberkas(String lokasiberkas) {
        this.lokasiberkas = lokasiberkas;
    }

    public String getNamaberkas() {
        return namaberkas;
    }

    public void setNamaberkas(String namaberkas) {
        this.namaberkas = namaberkas;
    }

    public void pengindeksanBaru() throws Exception {
        odb = new DatabaseOperation();
        

        odb.hapusTabel("berkas");
        odb.hapusTabel("kata");
        odb.hapusTabel("df");
        
        
    }

    public void periksa(String direktori) throws Exception {
        setLokasiberkas(direktori);
        File dir = new File(lokasiberkas);
        if (dir.isFile()){
            if (dir.getName().toLowerCase().endsWith(".txt")
                    || dir.getName().toLowerCase().endsWith(".doc")
                    || dir.getName().toLowerCase().endsWith(".xls")
                    || dir.getName().toLowerCase().endsWith(".ppt")
                    || dir.getName().toLowerCase().endsWith(".docx")
                    || dir.getName().toLowerCase().endsWith(".xlsx")
                    || dir.getName().toLowerCase().endsWith(".pptx")
                    || dir.getName().toLowerCase().endsWith(".odt")
                    || dir.getName().toLowerCase().endsWith(".ods")
                    || dir.getName().toLowerCase().endsWith(".odp")
                    || dir.getName().toLowerCase().endsWith(".pdf")
                    || dir.getName().toLowerCase().endsWith(".rtf")
                    || dir.getName().toLowerCase().endsWith(".htm")
                    || dir.getName().toLowerCase().endsWith(".html")) {
                System.out.println(dir.getName());
                System.out.println("Mencatat berkas...");
                simpanFileDB(dir.getName(), dir.getPath());
            }
        }
        if (dir.isDirectory()){
            if (!dir.getName().toLowerCase().endsWith("_files")) {
                String[] isiFolder = dir.list();
                String path = dir.getPath();

                for (int i = 0; i < isiFolder.length; i++) {
                    File berkas = new File(path, isiFolder[i]);
                    periksa(berkas.getPath());
                }
            } else {
                System.out.println("Direktori \"" + dir.getPath() + "\" tidak diikutkan dalam pencarian\n");
            }
        }
    }

    private void simpanFileDB(String namaberkas, String lokasiberkas) throws Exception {
        odb = new DatabaseOperation();
        

//        PreparedStatement query = odb.getConnection().prepareStatement("INSERT INTO berkas VALUES(null,?,?,0)");
//        query.setString(1, namaberkas);
//        query.setString(2, lokasiberkas);
//        query.executeUpdate();
        System.out.println("INSERT INTO berkas VALUES(null," + namaberkas + "," + lokasiberkas + ",0)");

        
    }

    public void indeksFile() throws Exception {
        odb = new DatabaseOperation();
        

        ResultSet result = odb.sqlSelect("SELECT lokasiberkas,namaberkas,idberkas FROM berkas WHERE status=0");

        int record = 0;
        int totalKata = 0;
        while (result.next()) {
            record++;
            // String judul = result.getString("namaberkas");      // ambil nama file
            int id = result.getInt("idberkas");                 // ambil id file
            String path = result.getString("lokasiberkas");     // ambil alamat file

            System.out.println("Memproses teks...");
            String teks = ot.getDocumentText(path);
            Analyzer an = ot.getAnalyzer();
            List<String> token = ot.tokenize(an, teks);
            int jumlah = 0;
            for (String kata : token) {
                if (token.contains(kata)) {
                    jumlah++;
                }
            }
            Iterator<String> i = token.iterator();
            while (i.hasNext()) {
                String katanya = i.next().toString();
                System.out.println(katanya);
                System.out.println("Menghitung kata...");

                // cek apakah kata sudah ada dalam database.
                // kalau sudah, lakukan UPDATE
                // kalau belum, lakukan INSERT
                katanya = katanya.replace("\'", "");
                updateJumlahKata(katanya, id);
            }
            totalKata = totalKata + jumlah;
            odb.sqlUpdate("UPDATE berkas SET status='1' WHERE idberkas='" + id + "'");
        }
        System.out.println("Semua dokumen sudah di indeks: " + record);
        System.out.println("Jumlah total kata : " + totalKata);
        System.out.println();
        result.close();

        
    }

    private void updateJumlahKata(String katanya, int id) throws Exception {
        System.out.println("SELECT kata,jumlah FROM kata WHERE kata='" + katanya + "' AND idberkas=" + id);
        ResultSet result = odb.sqlSelect("SELECT kata,jumlah FROM kata WHERE kata='" + katanya + "' AND idberkas=" + id);
        if (result.next()) {
            int jumKata = result.getInt("jumlah");
            jumKata++;
            System.out.println("UPDATE kata SET jumlah=" + jumKata + " WHERE kata='" + katanya + "' AND idberkas=" + id);
            odb.sqlUpdate("UPDATE kata SET jumlah=" + jumKata + " WHERE kata='" + katanya + "' AND idberkas=" + id);
        } else {
            System.out.println("INSERT INTO kata VALUES ('" + katanya + "'," + id + ",1,0,0)");
            odb.sqlUpdate("INSERT INTO kata VALUES ('" + katanya + "'," + id + ",1,0,0)");
        }
        result.close();
    }

    public void hitungTf() throws Exception {
        odb = new DatabaseOperation();
        

        ResultSet result = odb.sqlSelect("SELECT idberkas FROM berkas");
        System.out.println("SELECT idberkas FROM berkas");

        while (result.next()) {
            int iddok = result.getInt("idberkas");
            ResultSet result2 = odb.sqlSelect("SELECT SUM(jumlah) FROM kata WHERE idberkas=" + iddok);
            System.out.println("SELECT SUM(jumlah) FROM kata WHERE idberkas=" + iddok);

            while (result2.next()) {
                ResultSet result3 = odb.sqlSelect("SELECT kata,jumlah,idberkas FROM kata");
                System.out.println("SELECT kata,jumlah,idberkas FROM kata");

                int totalKata = result2.getInt("SUM(jumlah)");
                while (result3.next()) {
                    int dokid = result3.getInt("idberkas");
                    int jumlah = result3.getInt("jumlah");
                    String kata = result3.getString("kata");
                    double tf = (double) jumlah / totalKata;
                    //DecimalFormat desimal = new DecimalFormat("#.####");
                    //desimal.setRoundingMode(RoundingMode.HALF_EVEN);
                    //String desimalTf = desimal.format(tf);

                    System.out.println(kata + ", " + jumlah);
                    System.out.println("total kata : " + totalKata);
                    System.out.println(jumlah + "/" + totalKata + " = " + tf);

                    if (dokid == iddok) {
                        System.out.println("id sama, lanjut...");
                        System.out.println("UPDATE kata SET tf=" + tf + " WHERE kata='" + kata + "' AND idberkas=" + dokid);
                        odb.sqlUpdate("UPDATE kata SET tf=" + tf + " WHERE kata='" + kata + "' AND idberkas=" + dokid);
                    } else {
                        System.out.println("id beda, lewat...");
                    }
                }
                result3.close();
            }
            result2.close();
        }
        result.close();
        
    }

    public void hitungIdf() throws Exception {
        odb = new DatabaseOperation();
        

        ResultSet result = odb.sqlSelect("SELECT COUNT(idberkas) FROM berkas");
        System.out.println("SELECT COUNT(idberkas) FROM berkas");

        int N = 0;
        while (result.next()) {
            N = result.getInt("COUNT(idberkas)");
        }

        System.out.println("Jumlah dokumen : " + N);
        System.out.println();
        result.close();

        ResultSet result2 = odb.sqlSelect("SELECT kata, COUNT(kata) FROM kata GROUP BY kata");
        System.out.println("SELECT kata, COUNT(kata) FROM kata GROUP BY kata");

        String kata;
        int df;
        double idf;
        double x;
        while (result2.next()) {
            kata = result2.getString("kata");
            df = result2.getInt("COUNT(kata)");
            x = (double) N / df;
            idf = (double) Math.log10(x);
            System.out.println("jumlah seluruh dokumen = " + N);
            System.out.println("jumlah dokumen yang mengandung kata \"" + kata + "\" = " + df);
            System.out.println("idf = log(N / df) = log(" + (double) N / df + ") = " + (Math.log10(x)));
            //DecimalFormat desimal = new DecimalFormat("#.####");
            //desimal.setRoundingMode(RoundingMode.HALF_EVEN);
            //String desimalIdf = desimal.format(idf);

            odb.sqlUpdate("INSERT INTO df VALUES('" + kata + "'," + df + "," + idf + ")");
            System.out.println("INSERT INTO df VALUES('" + kata + "'," + df + "," + idf + ")");
        }
        result2.close();
        
    }

    public void hitungBobot() throws Exception {
        odb = new DatabaseOperation();
        

        ResultSet result = odb.sqlSelect("SELECT kata,idberkas,tf FROM kata");
        System.out.println("SELECT kata,idberkas,tf FROM kata");

        String kata;
        int dokid;
        double tf;
        while (result.next()) {
            kata = result.getString("kata");
            dokid = result.getInt("idberkas");
            tf = result.getDouble("tf");

            ResultSet result2 = odb.sqlSelect("SELECT idf FROM df WHERE kata='" + kata + "'");
            System.out.println("SELECT idf FROM df WHERE kata='" + kata + "'");

            while (result2.next()) {
                double idf = result2.getDouble("idf");
                double bobot = (double) tf * idf;
                //DecimalFormat desimal = new DecimalFormat("#.####");
                //desimal.setRoundingMode(RoundingMode.HALF_EVEN);
                //String desimalBobot = desimal.format(bobot);

                odb.sqlUpdate("UPDATE kata SET bobot=" + bobot + " WHERE kata='" + kata + "' AND idberkas=" + dokid);
                System.out.println("UPDATE kata SET bobot=" + bobot + " WHERE kata='" + kata + "' AND idberkas=" + dokid);
            }
            result2.close();
        }
        result.close();
        
    }

    public void buatTermDocumentMatrix() throws Exception {
        File file = new File("src/thesis/files/term-document.matrix");

        odb = new DatabaseOperation();
        

        ResultSet result5 = odb.sqlSelect("SELECT COUNT(idberkas) FROM berkas");
        System.out.println("SELECT COUNT(idberkas) FROM berkas");
        int jumlahdok = 0;
        while (result5.next()) {
            jumlahdok = result5.getInt("COUNT(idberkas)");
        }

        odb.sqlUpdate("ALTER TABLE df ORDER BY kata");

        ResultSet result2 = odb.sqlSelect("SELECT kata FROM df");
        System.out.println("SELECT kata FROM df");

        Writer output = new BufferedWriter(new FileWriter(file));
        // int i = 0;
        String kata;
        while (result2.next()) {
            // i++;
            kata = result2.getString("kata");

            int j = 0;
            ResultSet result3 = odb.sqlSelect("SELECT idberkas FROM berkas");
            System.out.println("SELECT idberkas FROM berkas");

            int iddok;
            while (result3.next()) {
                j++;
                iddok = result3.getInt("idberkas");

                ResultSet result4 = odb.sqlSelect("SELECT bobot FROM kata WHERE kata='" + kata + "' AND idberkas=" + iddok);
                System.out.print("SELECT bobot FROM kata WHERE kata='" + kata + "' AND idberkas=" + iddok);

                double bobot;
                if (result4.next()) {
                    bobot = result4.getDouble("bobot");
                    System.out.println(" (" + String.format("%1.16f", bobot) + ")");
                    output.append(String.format("%1.16f", bobot));
                    if (j != jumlahdok) {
                        output.append(" ");
                    }
                } else {
                    System.out.println(" (" + String.format("%1.16f", 0.0) + ")");
                    output.append(String.format("%1.16f", 0.0));
                    if (j != jumlahdok) {
                        output.append(" ");
                    }
                }
                result4.close();
            }
            output.append("\n");
            result3.close();
        }
        output.close();

        result2.close();
        result5.close();
        
    }
    
    public DoubleMatrix2D hitungVektorDokumen() throws Exception {
        om = new MatrixOperation();
        
        DoubleMatrix2D matriks = om.getMatriksTermDoc();
        om.cetakMatriks(matriks, "Matriks Term-Document");
        om.cetakMatriks(om.getU(), "Matriks U");
        om.cetakMatriks(om.getS(), "Matriks S");
        om.cetakMatriks(om.getV(), "Matriks V");
        
        DoubleMatrix2D lowRankU = om.getReducedU();
        om.cetakMatriks(lowRankU, "Matriks Low Rank U");

        DoubleMatrix2D lowRankS = om.getReducedS();
        om.cetakMatriks(lowRankS, "Matriks Low Rank S");

        DoubleMatrix2D lowRankV = om.getReducedV();
        om.cetakMatriks(lowRankV, "Matriks Low Rank V");

        DoubleMatrix2D vektorDokumen = om.transpose(lowRankV);
        om.cetakMatriks(vektorDokumen, "Vektor Dokumen");

        return vektorDokumen;
    }
}
